package com.da.auth.security.jwt;


import com.alibaba.fastjson.JSON;
import com.da.auth.entity.constant.DailyAuthConstant;
import com.da.auth.redis.RedisCache;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;


/**
 * @Author: hyacinth
 * @CreateTime: 2025-02-10
 * @Version: 1.0
 */
@Component
@Slf4j
@PropertySource("classpath:application.yml")
@RequiredArgsConstructor
public class JwtUtils {


    private final RedisTemplate<String, Object> redisTemplate;

    /**
     * 根据用户信息生成token
     *
     * @param claims 用户信息
     * @return
     */
    public String createJWT(Map<String, Object> claims) {

        // 生成JWT的时间
        Date exp = new Date(System.currentTimeMillis());
        // 创建 Calendar 实例，并将其时间设置为当前时间
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(exp);
        // 给时间加上 6 小时
        calendar.add(Calendar.HOUR_OF_DAY, 6);
        // 获取加上 6 小时后的时间
        Date newDate = calendar.getTime();
        log.info("exp: {}", newDate);

        // 将密钥转换为Key对象
        Key key = Keys.hmacShaKeyFor(DailyAuthConstant.TOKEN_PREFIX.getBytes(StandardCharsets.UTF_8));

        // 设置jwt的body
        JwtBuilder builder = Jwts.builder()
                // 如果有私有声明，一定要先设置这个自己创建的私有的声明，这个是给builder的claim赋值，一旦写在标准的声明赋值之后，就是覆盖了那些标准的声明的
                .setClaims(claims)
                // 设置签名使用的签名算法和签名使用的秘钥
                .signWith(key)
                // 设置过期时间
                .setExpiration(newDate);

        return builder.compact();
    }

    /**
     * Token解密
     *
     * @param token 加密后的token
     * @return
     */
    public Claims parseJWT(String token) {

        try {
            // 将密钥转换为Key对象
            Key key = Keys.hmacShaKeyFor(DailyAuthConstant.TOKEN_PREFIX.getBytes(StandardCharsets.UTF_8));
            token = token.replace("Daily ", "");
            // 解析 JWT
            Claims claims = Jwts.parserBuilder()
                    .setSigningKey(key)
                    .build()
                    .parseClaimsJws(token)
                    .getBody();
            log.info("caims: {}", JSON.toJSONString(claims));
            // 检查 token 是否过期
            Date expiration = claims.getExpiration();
            if (expiration != null && expiration.before(new Date())) {
                throw new ExpiredJwtException(null, claims, "Token has expired");
            }
            return claims;
        } catch (ExpiredJwtException e) {
            System.err.println("Token 已过期: " + e.getMessage());
            return null;
        } catch (JwtException e) {
            System.err.println("Token 验证失败: " + e.getMessage());
            return null;
        }
    }

    /**
     * 验证token
     *
     * @param token 待验证的token
     * @return
     */
    public boolean validateToken(String token) {
        boolean equals = Boolean.TRUE.equals(redisTemplate.hasKey(token));
        return equals;
    }

    /**
     * 刷新 Token
     *
     * @param token 待刷新的 Token
     */
    public void refreshToken(String token) {
        redisTemplate.expire(token, DailyAuthConstant.TOKEN_EXPIRATION, TimeUnit.MINUTES);
    }
}
